/**
 * fulihui.com Inc.
 * Copyright (c) 2015-2017 All Rights Reserved.
 */
package com.fulihui.wgj.auth.service.impl;

import com.fulihui.common.enums.MsgTypeEnum;
import com.fulihui.common.result.rpc.BaseResult;
import com.fulihui.weixinsdk.WeixinSDK;
import com.fulihui.weixinsdk.encrypt_decode.com.qq.weixin.mp.aes.AesException;
import com.fulihui.weixinsdk.encrypt_decode.com.qq.weixin.mp.aes.WXBizMsgCrypt;
import com.fulihui.weixinsdk.model.AuthorizationInfo;
import com.fulihui.weixinsdk.request.ApiQueryAuthRequest;
import com.fulihui.weixinsdk.request.customer.CustomerTextMsgRequest;
import com.fulihui.weixinsdk.result.ApiQueryAuthResult;
import com.fulihui.weixinsdk.util.XMLUtil;
import com.fulihui.wgj.auth.common.WxMsgBuild;
import com.fulihui.wgj.auth.config.WxIssueConfig;
import com.fulihui.wgj.auth.service.WeixinIssueTestService;
import com.fulihui.wgj.facade.msg.EventMsg;
import com.fulihui.wgj.facade.request.event.EventNotifyRequest;
import com.fulihui.wgj.facade.result.system.WxSystemConfigResult;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * 微信开放平台全网发布检测业务处理
 *
 * @author: Levon
 * @version: v 0.1 2017-06-05 14:49
 */
@Component
public class WeixinIssueTestServiceImpl implements WeixinIssueTestService {

    private static final Logger logger = LoggerFactory.getLogger(WeixinIssueTestServiceImpl.class);

    @Autowired
    WeixinSDK weixinSDK;
    @Autowired
    ThreadPoolTaskExecutor threadPool;
    @Autowired
    private WxIssueConfig wxIssueConfig;
//    @Resource
//    WeixinEventNotifyService openSdkService;

    @Override
    public String issueTest(EventNotifyRequest eventNotifyRequest) throws AesException {
        logger.info("微信全网发布检测-收到消息，eventNotifyRequest={}", eventNotifyRequest);
        WXBizMsgCrypt crypto = new WXBizMsgCrypt(wxIssueConfig.getToken(),
                wxIssueConfig.getEncodingAesKey(), wxIssueConfig.getAppId());
        String xml = crypto.decryptMsg(eventNotifyRequest.getMsg_signature(), eventNotifyRequest.getTimestamp(),
                eventNotifyRequest.getNonce(), eventNotifyRequest.getPostDate());
        logger.info("微信全网发布检测-接收到的xml解密xml={}", xml);
        EventMsg message = XMLUtil.parseObject(xml, EventMsg.class);
        message.setAppId(eventNotifyRequest.getAppId());
        if (message != null) {
            String msgType = message.getMsgType();
            logger.info("微信全网发布检测-收到消息，type={}", msgType);
            switch (msgType) {
                case "event":
                    return replyEventMsg(message, eventNotifyRequest);
                case "text":
                    return replyTextMsg(message, eventNotifyRequest);
                default:
                    return "";
            }
        }
        return "";
    }

    /**
     * 模拟粉丝触发专用测试公众号的事件，并推送事件消息到专用测试公众号，
     * 第三方平台方开发者需要提取推送XML信息中的event值，并在5秒内立即返回按照下述要求组装的文本消息给粉丝。
     *
     * @param message
     * @return
     */
    public String replyEventMsg(EventMsg message, EventNotifyRequest eventNotifyRequest) throws AesException {
        /*
           1) 微信推送给第三方平台方： 事件XML内容（与普通公众号接收到的信息是一样的）
           2) 服务方开发者在5秒内回应文本消息并最终触达到粉丝：文本消息的XML中Content字段的内容必须组装为：
              event + “from_callback”（假定event为LOCATION，则Content为: LOCATIONfrom_callback）
         */
        String reply = WxMsgBuild.buildTextMessage(message.getFromUserName(), message.getToUserName(),
                message.getEvent() + "from_callback");
        logger.info("微信全网发布-事件消息回复，msg={},touser={},fromuser={}", reply, message.getToUserName(), message.getFromUserName());
        // 回复的消息需要加密
        WXBizMsgCrypt crypto = new WXBizMsgCrypt(wxIssueConfig.getToken(),
                wxIssueConfig.getEncodingAesKey(), wxIssueConfig.getAppId());
        String msg = crypto.encryptMsg(reply, eventNotifyRequest.getTimestamp(), eventNotifyRequest.getNonce());
        return msg;
    }

    /**
     * 1： 模拟粉丝发送文本消息给专用测试公众号，第三方平台方需根据文本消息的内容进行相应的响应：
     * 2： 模拟粉丝发送文本消息给专用测试公众号，第三方平台方需在5秒内返回空串表明暂时不回复，然后再立即使用客服消息接口发送消息回复粉丝
     *
     * @param message
     * @return
     */
    private String replyTextMsg(EventMsg message, EventNotifyRequest eventNotifyRequest) throws AesException {

        if ("TESTCOMPONENT_MSG_TYPE_TEXT".equals(message.getContent())) {
           /*
              1) 微信模推送给第三方平台方：文本消息，其中Content字段的内容固定为：TESTCOMPONENT_MSG_TYPE_TEXT
              2) 第三方平台方立马回应文本消息并最终触达粉丝：Content必须固定为：TESTCOMPONENT_MSG_TYPE_TEXT_callback
             */
            String reply = WxMsgBuild.buildTextMessage(message.getFromUserName(), message.getToUserName(),
                    "TESTCOMPONENT_MSG_TYPE_TEXT_callback");
            logger.info("微信全网发布-固定文本消息回复，msg={},touser={},fromuser={}", reply, message.getToUserName(), message.getFromUserName());
            // 回复的消息需要加密
            WXBizMsgCrypt crypto = new WXBizMsgCrypt(wxIssueConfig.getToken(),
                    wxIssueConfig.getEncodingAesKey(), wxIssueConfig.getAppId());
            String msg = crypto.encryptMsg(reply, eventNotifyRequest.getTimestamp(), eventNotifyRequest.getNonce());
            return msg;
        } else {
            // 调用接口查询数据库中存放的第三方token凭证
            WxSystemConfigResult componentToken = null;// openSdkService.getComponentToken();
            logger.info("openSdkService getComponentToken response = {}", componentToken);
            if (componentToken != null && componentToken.getErrcode() != BaseResult.SUCCESS) {
                return "";
            }
            /*
                模拟粉丝发送文本消息给专用测试公众号，第三方平台方需在5秒内返回空串表明暂时不回复，
                然后再立即使用客服消息接口发送消息回复粉丝
             */
            if (StringUtils.startsWithIgnoreCase(message.getContent(), "QUERY_AUTH_CODE")) {
                logger.info("微信全网发布-异步触发客服消息，touser={},fromuser={}", message.getToUserName(), message.getFromUserName());
                threadPool.execute(() -> {
                    /*
                    1）微信模推送给第三方平台方：文本消息，其中Content字段的内容固定为： QUERY_AUTH_CODE:$query_auth_code$
                    （query_auth_code会在专用测试公众号自动授权给第三方平台方时，由微信后台推送给开发者）
                    2）第三方平台方拿到$query_auth_code$的值后，通过接口文档页中的“使用授权码换取公众号的授权信息”API，
                     将$query_auth_code$的值赋值给API所需的参数authorization_code。然后，调用发送客服消息api回复文本消息给粉丝，
                     其中文本消息的content字段设为：$query_auth_code$_from_api（其中$query_auth_code$需要替换成推送过来的query_auth_code）
                     */
                    logger.info("微信全网发布-authorizationCode={}", message.getContent());
                    ApiQueryAuthRequest queryAuthRequest = new ApiQueryAuthRequest();
                    queryAuthRequest.setComponent_appid(wxIssueConfig.getAppId());
                    // componet_access_token 从接口获取 全网发布检测的时候用
                    queryAuthRequest.setComponent_access_token(componentToken.getValue().getDescript());
                    String authorizationCode = message.getContent().split(":")[1];
                    queryAuthRequest.setAuthorization_code(authorizationCode);

                    ApiQueryAuthResult queryAuthResult = weixinSDK.invokeService(queryAuthRequest);
                    AuthorizationInfo info = queryAuthResult.getAuthorization_info();
                    String authorizer_access_token = info.getAuthorizer_access_token();

                    logger.info("微信全网发布-根据query_auth_code获取token，query_auth_code={},token={}", authorizationCode, authorizer_access_token);

                    CustomerTextMsgRequest request = new CustomerTextMsgRequest();
                    request.setAccess_token(authorizer_access_token);
                    request.setTouser(message.getFromUserName());
                    request.setMsgtype(MsgTypeEnum.text.getCode());
                    Map<String, String> content = Maps.newHashMap();
                    content.put("content", authorizationCode + "_from_api");
                    request.setText(content);
                    weixinSDK.invokeService(request);
                    logger.info("微信全网发布-异步发送消息，结束。request={}", request);
                });
            }
            return "";
        }
    }
}
